

-- @module : Controller
-- @author : ben


library ieee;
use ieee.std_logic_1164.all;

entity Controller is 
port (

    clk	: in bit;
    loadM : in bit;
    loadQ : in bit;
    start : in bit;
    reset : in bit;
    Q_zero : in bit;
    Q_prev : in bit;
    counter_overflow : in bit;
    
    clear : out bit;
    done : out bit;
    M_load : out bit;
    A_load : out bit;
    Q_load : out bit;
    M_hold : out bit;
    A_hold : out bit;
    Q_hold : out bit;
    Q_Prev_hold : out bit;
    add_notSub : out bit;
    counter_en : out bit
    
    ); 
     
end Controller;     
        

architecture rtl of Controller is
	type STATE is (reset_state,
	 load_m_state,
	 wait_for_q_state,
	 load_q_state,
	 check_Qbits_state,
	 add_state,
	 sub_state,
	 shift_state,
	 load_state,
	 done_state);
    signal CURRENT_STATE, NEXT_STATE: STATE := reset_state;             

signal inQcheckstate : bit := '0';
signal inShiftState : bit := '0';
signal lastAddSubNot : bit;

begin  

SEQ : process (clk, reset)
begin
    if (reset = '1') then
        CURRENT_STATE <= reset_state;
    elsif (CLK'EVENT and CLK = '1') then
        CURRENT_STATE <= NEXT_STATE;
    end if;
end process;

comb : process 

begin
    
    wait for 1 ns;
    
    M_load <= '0';
    A_load <= '0';
    Q_load <= '0';
    M_hold <= '1';
    A_hold <= '1';
    Q_hold <= '1';
    Q_Prev_hold <= '1';
    counter_en <= '0';
    add_notSub <= '1';
    done <= '0';
    inQcheckstate <= '0';
    inShiftState <= '0';
    clear <= '1';
    
    case CURRENT_STATE is
        
        when reset_state => clear <= '0';
        	if (loadm = '1') then 
        		NEXT_STATE <= load_m_state;
        		clear <= '1';
        	else
        	    NEXT_STATE <= reset_state;
    	    end if;
    	    
	    when load_m_state => M_load <= '1';
	    	NEXT_STATE <= wait_for_q_state;
	    	
	    when wait_for_q_state => 
    	    if (loadq = '1') then
    	    	    NEXT_STATE <= load_q_state;
    	    	else
    	    	    NEXT_STATE <= wait_for_q_state;
    	    	end if;
	    	
	    when load_q_state => Q_load <= '1';
	    	if (start = '1') then
	    	    NEXT_STATE <= check_Qbits_state;
	    	else
	    	    NEXT_STATE <= load_q_state;
	    	    q_load <= '0';
	    	end if;
	    
	    when check_Qbits_state =>
	    
	    	NEXT_STATE <= check_Qbits_state;	    
	    
	    	inQcheckstate <= '1';
	    
	    	if (q_zero = '1' and Q_prev = '0') then
	    	    NEXT_STATE <= sub_state;
	    	end if;
	    	
	    	if (q_zero = '0' and Q_prev = '1') then
	    	    NEXT_STATE <= add_state;
	    	end if;
	    	
	    	if (Q_zero = Q_prev) then
	    	    Q_Prev_hold <= '0';
	    		NEXT_STATE <= shift_state;
	    	end if;
	    	
	   when shift_state => A_hold <= '0'; Q_hold <= '0'; counter_en <= '1';  Q_Prev_hold <= '0';
	   		inShiftState <= '1';
	   		NEXT_STATE <= check_Qbits_state;
	   		
	   		if (counter_overflow = '1') then
	   		    NEXT_STATE <= done_state;
	   		end if; 
	   		
	   when sub_state => add_notSub <= '0';
	   		lastAddSubNot <= '0';
	   		NEXT_STATE <= load_state;
	   		
	   when add_state =>
	   		lastAddSubNot <= '1';
	   		NEXT_STATE <= load_state;
	   		
	   when load_state =>
	   		add_notSub <= lastAddSubNot;
	   		A_load <= '1';
	   		NEXT_STATE <= shift_state;
	   		
	   when done_state => done <= '1';
	   	
	 end case;
end process;

end rtl;
